package com.atguigu.gmall0218.payment.controller.third;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.atguigu.gmall0218.bean.PaymentInfo;
import com.atguigu.gmall0218.bean.PaymentInfoException;
import com.atguigu.gmall0218.bean.enums.PayOrg;
import com.atguigu.gmall0218.bean.enums.PaymentStatus;
import com.atguigu.gmall0218.payment.config.AlipayConfig;
import com.atguigu.gmall0218.payment.service.impl.PayCenterCombSVImpl;
import com.atguigu.gmall0218.payment.service.impl.PaymentExceptionServiceImpl;
import com.atguigu.gmall0218.payment.service.impl.PaymentServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <pre>
 *    @author  : liquid
 *    email   : xiaokui.li@guigu.com
 *    desc    : 支付宝支付
 *    version : v1.0
 * </pre>
 */
@Controller
@RequestMapping("alipay/")
public class AliPayController {
    @Autowired
    private AlipayClient alipayClient;
    @Autowired
    private PayCenterCombSVImpl payCenterCombSV;
    @Autowired
    private PaymentServiceImpl paymentSerivce;
    @Autowired
    private PaymentExceptionServiceImpl paymentExceptionService;
    @RequestMapping("webPayment/alipayapi")
    public void pay(HttpServletRequest request, HttpServletResponse response) throws Exception{
        //创建支付记录
        String orderId = request.getParameter("orderId");
        //创建API对应的request
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        // 设置同步回调
        alipayRequest.setReturnUrl(AlipayConfig.return_payment_url);
        // 设置异步回调
        alipayRequest.setNotifyUrl(AlipayConfig.notify_payment_url);
        // 声明一个map 集合来存储参数
        HashMap<String, Object> map = new HashMap<>();
        map.put("out_trade_no",orderId);
        map.put("product_code","FAST_INSTANT_TRADE_PAY");
//        map.put("total_amount",paymentInfo.getTotalAmount());
        map.put("total_amount",0.01);
        map.put("subject","给尚硅谷学费");
//        map.put("subject",paymentInfo.getSubject());
        // 将封装好的参数传递给支付宝！
        alipayRequest.setBizContent(JSON.toJSONString(map));
        String form="";
        try {
            //调用SDK生成表单
            form = alipayClient.pageExecute(alipayRequest).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        response.setContentType("text/html;charset=UTF-8");
        try {
            //直接将完整的表单html输出到页面
            response.getWriter().write(form);
            response.getWriter().flush();
            response.getWriter().close();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
    }

    @RequestMapping("callback/return")
    @ResponseBody
    public String callbackReturn(){
        return "success";
//        return "redirect:"+AlipayConfig.return_order_url;
    }
    // 异步回调
    @RequestMapping("callback/notify")
    @ResponseBody
    public String callbackNotify(@RequestParam Map<String,String> paramMap, HttpServletRequest request,HttpServletResponse response){

        // Map<String, String> paramsMap = ... //将异步通知中收到的所有参数都存放到map中
        //调用SDK验证签名
        boolean flag = false;
        try {
            flag = AlipaySignature.rsaCheckV1(paramMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        if(flag){
            // TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure
            // 对业务的二次校验
            // 只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
            // 支付成功之后，需要做什么？
            // 需要得到trade_status
            String trade_status = paramMap.get("trade_status");
            // 通过out_trade_no 查询支付状态记录 订单号
            String out_trade_no = paramMap.get("out_trade_no");
            //支付宝交易流水号
            String trade_no = paramMap.get("trade_no");
            try {
                //模拟网络抖动
                Thread.sleep(120000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // String total_amount = paramMap.get("total_amount");
            if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)){
                // 当前的订单支付状态如果是已经付款，或者是关闭
                // select * from paymentInfo where out_trade_no =?
                PaymentInfo paymentInfoQuery = new PaymentInfo();
                paymentInfoQuery.setOutTradeNo(out_trade_no);
                PaymentInfo paymentInfo = paymentSerivce.getPaymentInfo(paymentInfoQuery);

                if (paymentInfo.getPaymentStatus()== PaymentStatus.PAID || paymentInfo.getPaymentStatus()==PaymentStatus.ClOSED){
                    // 判断是否是同一个第三方流水号，如果是，则不操作，否则存入异常单
                    if (trade_no.equals(paymentInfo.getPayTradeNo())){
                        //表示，这是支付宝重复发送的异步通知，支付中心不做任何处理
                        return "success";
                    }
                    //存入异常单，表示是多种支付方式的重复支付
                    PaymentInfoException paymentInfoException = new PaymentInfoException();
                    this.savePayException(out_trade_no, paymentInfo, paymentInfoException);
                    //todo 发送异常消息通知退款接口，随便选择其中一个即可 或者显示退款按钮等等，主要看产品设计

                    return "success";
                }
                // 更新交易记录的状态！
                payCenterCombSV.updatePayCenter(out_trade_no,trade_no);
                // 发送消息队列给订单：orderId, result ,系统来源（订单系统，账务系统，）
//                paymentSerivce.sendPaymentResult(paymentInfo,"success");
                return "success";
            }
        }else{
            // TODO 验签失败则记录异常日志，并在response中返回failure.
            return "failure";
        }
        return "failure";
    }

    /**
     * 保存异常单
     * @param out_trade_no 第三方流水号
     * @param paymentInfo 支付信息
     * @param paymentInfoException  支付异常单信息
     */
    protected void savePayException(String out_trade_no, PaymentInfo paymentInfo, PaymentInfoException paymentInfoException) {
        paymentInfoException.setOrderId(paymentInfo.getOrderId());
        paymentInfoException.setOutTradeNo(out_trade_no);
        paymentInfoException.setPayOrgId(PayOrg.ZFB.getPayName());
        paymentInfoException.setPayTradeNo(paymentInfo.getPayTradeNo());
        paymentInfoException.setSubject(paymentInfo.getSubject());
        paymentInfoException.setTotalAmount(paymentInfo.getTotalAmount());
        paymentInfoException.setPaymentStatus(PaymentStatus.REPEAT);
        paymentExceptionService.savePaymentInfoException(paymentInfoException);
    }
}
